home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
misc
/
emu
/
msh-156.lha
/
han
/
pack.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-12-22
|
36KB
|
1,360 lines
/*-
* $Id: pack.c,v 1.56 1996/12/22 00:22:33 Rhialto Rel $
* $Log: pack.c,v $
* Revision 1.56 1996/12/22 00:22:33 Rhialto
* Better (but not perfect) device list deadlock handling.
* Add some Guru Book packets.
* Pretend success on ACTION_SET_COMMENT.
* Support for proper taskwait hook.
*
* Revision 1.55 1993/12/30 23:02:45 Rhialto
* Add code to reflect changing disk capacity to Mount info.
* Don't fail Info() if there is no disk in drive.
* SameLock() was wrong because TADM was wrong.
* Add Format() packet.
* Use 2.0+ calls for manipulating the device list, if possible.
* New LONGNAMES filesystem, changes throughout the handler.
* Optional (compile-time) broadcast IECLASS_DISKINSERTED messages.
* Freeze for MAXON5.
*
* Revision 1.54 1993/06/24 05:12:49 Rhialto
* DICE 2.07.54R.
*
* Revision 1.53 92/10/25 02:23:50 Rhialto
* Add 2.0 stuff.
*
* Revision 1.51 92/04/17 15:34:59 Rhialto
* Freeze for MAXON. DosType->Interleave; extra uninhibits fixed.
*
* Revision 1.46 91/10/06 18:26:16 Rhialto
*
* Freeze for MAXON
*
* Revision 1.43 91/09/28 01:35:36 Rhialto
* Changed to newer syslog stuff.
*
* Revision 1.42 91/06/13 23:46:21 Rhialto
* DICE conversion
*
* Revision 1.40 91/03/03 17:45:09 Rhialto
* Freeze for MAXON
*
* Revision 1.32 90/11/23 23:53:22 Rhialto
* Prepare for syslog
*
* Revision 1.31 90/11/10 02:42:38 Rhialto
* Patch 3a.
*
* Revision 1.30 90/06/04 23:15:58 Rhialto
* Release 1 Patch 3
*
* Originally:
*
* DOSDEVICE.C V1.10 2 November 1987
*
* EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C PUBLIC DOMAIN.
*
* By Matthew Dillon.
*
* This has been stripped and refilled with messydos code
* by Olaf Seibert.
*
* This code is (C) Copyright 1989-1992 by Olaf Seibert. All rights reserved.
* May not be used or copied without a licence.
*
* This file forms the interface between the actual handler code and all
* AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
* FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
* Also, most protection against non-inserted disks is done here.
-*/
#include "han.h"
#include "dos.h"
#include <string.h>
#if HDEBUG
# include "syslog.h"
#else
# define debug(x)
#endif
#define MSFL(something) ((struct MSFileLock *)(something))
#define MSFH(something) ((struct MSFileHandle *)(something))
Prototype struct MsgPort *DosPort;
Prototype struct DeviceNode *DevNode;
Prototype struct DeviceList *VolNode;
Prototype short DiskChanged;
Prototype long UnitNr;
Prototype char *DevName;
Prototype ulong DevFlags;
Prototype long Interleave;
Prototype struct DosEnvec *Environ;
Prototype struct DosPacket *DosPacket;
Prototype short Inhibited;
Prototype struct DeviceList *NewVolNode(char *name, struct DateStamp *date);
Prototype int MayFreeVolNode(struct DeviceList *volnode);
Prototype void FreeVolNode(struct DeviceList *volnode);
Prototype void FreeVolNodeDeferred(void);
Prototype struct FileLock *NewFileLock(struct MSFileLock *msfl, struct FileLock *fl);
Prototype long FreeFileLock(struct FileLock *lock);
Prototype long DiskRemoved(void);
Prototype void DiskInserted(struct DeviceList *volnode);
Prototype void CheckDriveType(void);
Prototype struct DeviceList *WhichDiskInserted(void);
Prototype void DiskChange(void);
Prototype int CheckRead(struct FileLock *lock);
Prototype int CheckWrite(struct FileLock *lock);
__stkargs /*__geta4*/ void ChangeIntHand(void);
__stkargs void ChangeIntHand0(void);
char *rega4(void);
Local void NewVolNodeName(void);
Local BPTR MakeFileLock(struct MSFileLock *msfl, struct FileLock *fl, long mode);
/*
* Since this code might be called several times in a row without being
* unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!! This also goes
* for any global/static assignments that might be changed by running the
* code.
*/
struct MsgPort *DosPort; /* Our DOS port... */
struct DeviceNode *DevNode; /* Our DOS node.. created by DOS for us */
struct DeviceList *VolNode; /* Device List structure for our volume
* node */
struct DeviceList *MustFreeVolNode; /* Deferred free. Just place for one. */
struct DosLibrary *DOSBase; /* DOS library base */
long PortMask; /* The signal mask for our DosPort */
long WaitMask; /* The signal mask to wait for */
short DiskChanged; /* Set by disk change interrupt */
short Inhibited; /* Are we inhibited (ACTION_INHIBIT)? */
long UnitNr; /* From */
char *DevName; /* the */
ulong DevFlags; /* mountlist */
long Interleave;
struct DosEnvec *Environ;
struct DosPacket *DosPacket; /* For the SystemRequest pr_WindowPtr */
long OpenCount; /* How many open files/locks/other
* references there are */
short WriteProtect; /* Are we software-writeprotected? */
struct Interrupt ChangeInt = {
{ 0 }, /* is_Node */
0, /* is_Data */
ChangeIntHand0 /* is_Code */
};
/*
* Don't call the entry point main(). This way, if you make a mistake
* with the compile options you'll get a link error.
*/
void
messydoshandler(void)
{
struct DosPacket *packet;
#if ! TASKWAIT
struct Message *msg;
#endif
struct Process *myproc;
short done;
struct FileSysStartupMsg *fssm;
/*
* Initialize all global variables. SysBase MUST be initialized
* before we can make Exec calls. AbsExecBase is a library symbol
* referencing absolute memory location 4.
*/
DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 0L);
#if HDEBUG
/*
* Initialize debugging code as soon as possible. Only SysBase required.
*/
initsyslog();
#endif /* HDEBUG */
myproc = (struct Process *)FindTask(NULL);
DosPort = &myproc->pr_MsgPort;
#if TASKWAIT
packet = taskwait(myproc);
#else
WaitPort(DosPort); /* Get Startup Packet */
msg = GetMsg(DosPort);
packet = (struct DosPacket *) msg->mn_Node.ln_Name;
#endif
DevNode = BTOC(PArg3);
{
ulong Reserved;
DevName = "messydisk.device";
UnitNr = 0;
DevFlags = 0;
MaxCache = 5;
BufMemType = MEMF_PUBLIC;
DefaultDisk.nsides = MS_NSIDES;
DefaultDisk.spt = MS_SPT;
DefaultDisk.bps = MS_BPS;
Partition.offset = 0;
Reserved = 0;
Interleave = 0;
if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
/* Same as BTOC(packet->dp_Arg2) */
UnitNr = fssm->fssm_Unit;
if (fssm->fssm_Device)
DevName = (char *)BTOC(fssm->fssm_Device)+1;
DevFlags = fssm->fssm_Flags;
if (Environ = (void *)BTOC(fssm->fssm_Environ)) {
debug(("Environ size %ld\n", Environ->de_TableSize));
if (Environ->de_TableSize >= DE_NUMBUFFERS) {
MaxCache = Environ->de_NumBuffers;
DefaultDisk.nsides = Environ->de_Surfaces;
DefaultDisk.spt = Environ->de_BlocksPerTrack;
DefaultDisk.bps = Environ->de_SizeBlock * 4;
debug(("DefaultDisk.bps %ld\n", (long)DefaultDisk.bps));
Partition.offset = Environ->de_LowCyl;
Reserved = Environ->de_Reserved;
/* Compatibility with old DosType = 1 */
Interleave = Environ->de_DosType;
if (Interleave == 1) {
Interleave = NICE_TO_DFx;
} else {
Interleave = Environ->de_Interleave;
}
#define get(xx,yy) if (Environ->de_TableSize >= yy) xx = ((ULONG*)Environ)[yy];
get(BufMemType, DE_MEMBUFTYPE);
} else
Environ = NULL;
#undef get
}
}
Disk = DefaultDisk;
Partition.offset *= Disk.bps * Disk.spt * Disk.nsides;
Partition.offset += Disk.bps * Reserved;
/* These values are used only for floppies (i.e. DRIVE*) */
if (Disk.spt <= MS_SPT_MAX_DD) {
Partition.spt_dd = Disk.spt;
Partition.spt_hd = Disk.spt * 2;
} else {
Partition.spt_hd = Disk.spt;
Partition.spt_dd = Disk.spt / 2;
}
debug(("offset %x, spt_dd %d, spt_hd %d\n",
Partition.offset, Partition.spt_dd, Partition.spt_hd));
}
if (DOSBase && HanOpenUp()) {
/*
* Loading DevNode->dn_Task causes DOS *NOT* to startup a new
* instance of the device driver for every reference. E.G. if
* you were writing a CON: device you would want this field to be
* NULL.
*/
DevNode->dn_Task = DosPort;
PRes1 = DOSTRUE;
PRes2 = 0;
} else { /* couldn't open dos.library */
PRes1 = DOSFALSE;
PRes2 = ERROR_DEVICE_NOT_MOUNTED; /* no better message available */
returnpacket(packet);
goto exit; /* exit process */
}
debug(("Returning startup packet %lx\n", packet));
returnpacket(packet);
/* Initialize some more global variables */
PortMask = 1L << DosPort->mp_SigBit;
VolNode = NULL;
WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
ChangeInt.is_Data = rega4(); /* for PURE code */
TDAddChangeInt(&ChangeInt);
OpenCount = 0;
Inhibited = 0;
/* Get the first real packet */
debug(("Awaiting first real dos packet\n"));
#if TASKWAIT
packet = taskwait(myproc);
debug(("got it: %lx\n", packet));
#else
WaitPort(DosPort);
msg = GetMsg(DosPort);
debug(("got it: %lx\n", msg));
#endif
done = -1;
DiskInserted(WhichDiskInserted());
goto entry;
/*
* Here begins the endless loop, waiting for requests over our message
* port and executing them. Since requests are sent over the message
* port in our device and volume nodes, we must not use our Process
* message port for this: this precludes being able to call DOS
* functions ourselves.
*/
top:
for (done = -1; done < 0;) {
Wait(WaitMask);
if (DiskChanged)
DiskChange();
#if TASKWAIT
while (packetsqueued()) { /* } */
#else
while (msg = GetMsg(DosPort)) {
#endif
byte buf[256]; /* Max length of BCPL strings is
* 255 + 1 for \0. */
#if TASKWAIT
packet = taskwait(myproc);
#endif
entry:
if (MustFreeVolNode)
FreeVolNodeDeferred();
if (DiskChanged)
DiskChange();
#if ! TASKWAIT
packet = (PACKET *) msg->mn_Node.ln_Name;
#endif
PRes1 = DOSFALSE;
PRes2 = 0;
error = 0;
debug(("Packet: %4ld %08lx %08lx %08lx %s\n",
PType, PArg1, PArg2, PArg3, typetostr(PType)));
DosPacket = packet; /* For the System Requesters */
switch (PType) {
case ACTION_DIE: /* attempt to die? */
done = (PArg1 == MSH_MAGIC) ? PArg2 : 0; /* Argh! Hack! */
break;
case ACTION_CURRENT_VOLUME: /* fharg1,Magic,Count -> VolNode,UnitNr,Private */
if (PArg2 == MSH_MAGIC) {
PArg2 = (long)PrivateInfo();
if (PArg3 > 0) {
OpenCount++;
} else if (PArg3 < 0) {
OpenCount--;
}
}
PRes1 = (long) CTOB(VolNode);
PRes2 = UnitNr;
break;
case ACTION_LOCATE_OBJECT: /* Lock,Name,Mode Lock */
{
struct FileLock *lock;
struct MSFileLock *msfl;
long lockmode;
lock = BTOC(PArg1);
if (CheckRead(lock))
break;
btos((byte *)PArg2, buf);
if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
lockmode = SHARED_LOCK;
msfl = MSLock(MSFL(lock ? lock->fl_Key : 0),
buf,
lockmode);
PRes1 = MakeFileLock(msfl, lock, lockmode);
}
break;
case ACTION_RENAME_DISK: /* BSTR:NewName Bool */
if (CheckWrite(NULL))
break;
btos((byte *)PArg1, buf);
buf[31] = '\0';
if (PRes1 = MSRelabel(buf))
NewVolNodeName();
break;
case ACTION_FREE_LOCK: /* Lock Bool */
{
struct FileLock *lock;
struct MSFileLock *msfl;
PRes1 = DOSTRUE;
lock = BTOC(PArg1);
if (lock == NULL)
break;
msfl = MSFL(lock->fl_Key);
FreeFileLock(lock); /* may remove last lock on volume */
MSUnLock(msfl); /* may call MayFreeVolNode */
}
break;
case ACTION_DELETE_OBJECT: /* Lock,Name Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
if (CheckWrite(lock))
break;
btos((byte *)PArg2, buf);
PRes1 = MSDeleteFile(MSFL(lock ? lock->fl_Key : 0),
buf);
}
break;
case ACTION_RENAME_OBJECT: /* SLock,SName,DLock,DName Bool */
{
struct FileLock *slock, *dlock;
char buf2[256];
slock = BTOC(PArg1);
dlock = BTOC(PArg3);
if (CheckWrite(slock) || CheckWrite(dlock))
break;
btos((byte *)PArg2, buf);
btos((byte *)PArg4, buf2);
PRes1 = MSRename(MSFL(slock ? slock->fl_Key : 0),
buf,
MSFL(dlock ? dlock->fl_Key : 0),
buf2);
}
break;
case ACTION_MORECACHE: /* #BufsToAdd bool,numbufs */
if ((MaxCache += (short) PArg1) <= 0) {
MaxCache = 1;
}
PRes1 = MaxCache; /* observed behaviour in std filesystem */
PRes2 = MaxCache; /* documented behaviour in manual */
debug(("Now %ld cache sectors\n", (long)MaxCache));
break;
case ACTION_COPY_DIR: /* Lock Lock */
{
struct FileLock *lock;
struct MSFileLock *msfl;
lock = BTOC(PArg1);
msfl = MSDupLock(MSFL(lock ? lock->fl_Key : 0));
PRes1 = MakeFileLock(msfl, lock,
lock ? lock->fl_Access : SHARED_LOCK);
}
break;
case ACTION_SET_PROTECT: /* -,Lock,Name,Mask Bool */
{
struct FileLock *lock;
lock = BTOC(PArg2);
if (CheckWrite(lock))
break;
btos((byte *)PArg3, buf);
PRes1 = MSSetProtect(MSFL(lock ? lock->fl_Key : 0),
buf, PArg4);
}
break;
case ACTION_CREATE_DIR: /* Lock,Name Lock */
{
struct FileLock *lock;
struct MSFileLock *msfl;
lock = BTOC(PArg1);
if (CheckWrite(lock))
break;
btos((byte *)PArg2, buf);
msfl = MSCreateDir(MSFL(lock ? lock->fl_Key : 0),
buf);
PRes1 = MakeFileLock(msfl, lock, SHARED_LOCK);
}
break;
case ACTION_EXAMINE_OBJECT: /* Lock,Fib Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
/*
if (CheckRead(lock))
break;
*/
PRes1 = MSExamine(MSFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
case ACTION_EXAMINE_NEXT: /* Lock,Fib Bool */
{
struct FileLock *lock;
lock = BTOC(PArg1);
if (CheckRead(lock))
break;
PRes1 = MSExNext(MSFL(lock ? lock->fl_Key : 0),
BTOC(PArg2));
}
break;
case ACTION_DISK_INFO: /* InfoData Bool:TRUE */
PRes1 = MSDiskInfo(BTOC(PArg1));
break;
case ACTION_INFO: /* Lock,InfoData Bool:TRUE */
if (CheckRead(BTOC(PArg1)))
break;
PRes1 = MSDiskInfo(BTOC(PArg2));
break;
case ACTION_FLUSH: /* writeout bufs, disk motor off */
MSUpdate(1);
break;
case ACTION_SET_COMMENT: /* -,Lock,Name,Comment Bool */
/* pretend to succeed so that COPY CLONE does not give up */
PRes1 = DOSTRUE;
break;
case ACTION_PARENT: /* Lock ParentLock */
{
struct FileLock *lock;
struct MSFileLock *msfl;
lock = BTOC(PArg1);
msfl = MSParentDir(MSFL(lock ? lock->fl_Key : 0));
PRes1 = MakeFileLock(msfl, lock, SHARED_LOCK);
}
break;
case ACTION_INHIBIT: /* Bool Bool */
if (PArg1) {
++Inhibited;
if (Inhibited == 1)
DiskRemoved();
IDDiskType = 'BUSY';/* GURU book p. 443 */
} else {
--Inhibited;
if (Inhibited < 0) {
Inhibited = 0; /* Do nothing if already uninhibited */
} else if (Inhibited == 0) {
DiskChange();
}
}
PRes1 = DOSTRUE;
error = 0;
break;
case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp Bool */
{
struct FileLock *lock;
lock = BTOC(PArg2);
if (CheckWrite(lock))
break;
btos((byte *)PArg3, buf);
PRes1 = MSSetDate(MSFL(lock ? lock->fl_Key : 0),
buf,
(struct DateStamp *)PArg4);
}
break;
#ifdef ACTION_SAME_LOCK
case ACTION_SAME_LOCK: /* Lock1,Lock2 Result */
{
struct FileLock *fl1, *fl2;
fl1 = BTOC(PArg1);
fl2 = BTOC(PArg2);
if (fl1->fl_Volume == fl2->fl_Volume) {
PRes1 = MSSameLock(MSFL(fl1->fl_Key),
MSFL(fl2->fl_Key));
} else {
PRes1 = DOSFALSE;
error = ERROR_DEVICE_NOT_MOUNTED;
}
}
break;
#endif
case ACTION_READ: /* FHArg1,CPTRBuffer,Length ActLength */
if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
CheckRead(NULL)) {
PRes1 = -1;
} else
PRes1 = MSRead(MSFH(PArg1), (byte *)PArg2, PArg3);
break;
case ACTION_WRITE: /* FHArg1,CPTRBuffer,Length ActLength */
if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
CheckWrite(NULL)) {
PRes1 = -1;
} else
PRes1 = MSWrite(MSFH(PArg1), (byte *)PArg2, PArg3);
break;
case ACTION_FINDUPDATE: /* FileHandle,Lock,Name Bool */
case ACTION_FINDINPUT: /* FileHandle,Lock,Name Bool */
goto open_notnew;
case ACTION_FINDOUTPUT: /* FileHandle,Lock,Name Bool */
{
struct MSFileHandle *msfh;
struct FileHandle *fh;
struct FileLock *lock;
if (CheckWrite(BTOC(PArg2)))
break;
open_notnew:
fh = BTOC(PArg1);
lock = BTOC(PArg2);
if (CheckRead(lock))
break;
btos((byte *)PArg3, buf);
debug(("'%s' ", buf));
msfh = MSOpen(MSFL(lock ? lock->fl_Key : 0),
buf,
PType);
if (msfh) {
fh->fh_Arg1 = (long) msfh;
PRes1 = DOSTRUE;
OpenCount++;
}
}
break;
case ACTION_END: /* FHArg1 Bool:Success */
PRes1 = MSClose(MSFH(PArg1));
OpenCount--;
break;
case ACTION_SEEK: /* FHArg1,Position,Mode OldPosition */
if (CheckLock(MSFH(PArg1)->msfh_FileLock) ||
CheckRead(NULL)) {
PRes1 = -1;
} else
PRes1 = MSSeek(MSFH(PArg1), PArg2, PArg3);
break;
case ACTION_FORMAT: /* vol,type Bool:success */
btos((byte *)PArg1, buf);
PRes1 = MSFormat(buf, PArg2);
break;
#ifdef ACTION_SET_FILE_SIZE /* FHArg1, off, whence Bool:success */
case ACTION_SET_FILE_SIZE:
PRes1 = MSSetFileSize(MSFH(PArg1), PArg2, PArg3);
break;
#endif
#ifdef ACTION_WRITE_PROTECT /* Bool:protect, passkey Bool:success */
case ACTION_WRITE_PROTECT:
{
static long Passkey;
if (PArg1) {
if (Passkey == 0) {
WriteProtect = 1;
Passkey = PArg2;
PRes1 = DOSTRUE;
}
} else {
if (Passkey == 0 || PArg2 == Passkey) {
WriteProtect = 0;
Passkey = 0;
PRes1 = DOSTRUE;
}
}
}
break;
#endif
#ifdef ACTION_FH_FROM_LOCK /* FH,Lock BOOL */
case ACTION_FH_FROM_LOCK:
{
struct MSFileHandle *msfh;
struct FileHandle *fh;
struct FileLock *lock;
fh = BTOC(PArg1);
lock = BTOC(PArg2);
if (CheckRead(lock))
break;
msfh = MSOpenFromLock(MSFL(lock ? lock->fl_Key : 0));
if (msfh) {
fh->fh_Arg1 = (long) msfh;
PRes1 = DOSTRUE;
OpenCount++;
/* Discard the lock */
FreeFileLock(lock);
}
}
break;
#endif
#ifdef ACTION_IS_FILESYSTEM
case ACTION_IS_FILESYSTEM: /* - Bool:TRUE */
PRes1 = DOSTRUE;
break;
#endif
#ifdef ACTION_CHANGE_MODE
case ACTION_CHANGE_MODE:
switch (PArg1) {
case CHANGE_FH:
PRes1 = MSChangeModeFH(MSFH(((struct FileHandle *)
BTOC(PArg2))->fh_Arg1), PArg3);
break;
case CHANGE_LOCK:
PRes1 = MSChangeModeLock(MSFL(((struct FileLock *)
BTOC(PArg2))->fl_Key), PArg3);
break;
}
break;
#endif
#ifdef ACTION_COPY_DIR_FH
case ACTION_COPY_DIR_FH: /* fh_Arg1 Lock */
case ACTION_PARENT_FH:
{
struct MSFileLock *msfl;
if (PType == ACTION_PARENT_FH)
msfl = MSParentOfFH(MSFH(PArg1));
else
msfl = MSDupLockFromFH(MSFH(PArg1));
/*
msfl = ((PType == ACTION_PARENT_FH) ?
MSParentOfFH : MSDupLockFromFH) (MSFH(PArg1));
*/
/* User has inserted disk by now, so we can use VolNode */
PRes1 = MakeFileLock(msfl, NULL, SHARED_LOCK);
}
break;
#endif
#ifdef ACTION_EXAMINE_FH
case ACTION_EXAMINE_FH: /* fh_Arg1,Fib Bool */
PRes1 = MSExamineFH(MSFH(PArg1), BTOC(PArg2));
break;
#endif
/* These packets by suggestion of the Amiga Guru Book: */
#if defined(ACTION_SERIALIZE_DISK)
case ACTION_SERIALIZE_DISK:
PRes1 = MSSerializeDisk();
break;
#endif
#if defined(ACTION_GET_DISK_FSSM)
case ACTION_GET_DISK_FSSM:
PRes1 = (ULONG)fssm;
OpenCount++;
break;
case ACTION_FREE_DISK_FSSM:
PRes1 = DOSTRUE;
OpenCount--;
break;
#endif
/*
* A few other packet types which we do not support
*/
/* case ACTION_WAIT_CHAR: / * Timeout, ticks Bool */
/* case ACTION_RAWMODE: / * Bool(-1:RAW 0:CON) OldState */
default:
PRes1 = DOSFALSE;
error = ERROR_ACTION_NOT_KNOWN;
break;
} /* end switch */
if (packet) {
if (error)
PRes2 = error;
debug(("RES=%06lx, ERR=%ld\n", PRes1, error));
returnpacket(packet);
DosPacket = NULL;
}
#if HDEBUG
else {
debug(("NO REPLY\n"));
}
#endif
} /* end while (GetMsg()) */
/*
* Now check for an other cause of events: timer IO.
* Unfortunately we cannot be sure that we always get a signal
* when the timeout has elapsed, since the same message port is
* used for other IO.
*/
if (CheckIO(&TimeIOReq->tr_node)) { /* Timer finished? */
debug(("TimeIOReq is finished\n"));
MSUpdate(0); /* Also may switch off motor */
}
} /* end for (;done) */
#if HDEBUG
debug(("Can we remove ourselves? "));
#endif /* HDEBUG */
Forbid();
if (OpenCount || packetsqueued()) {
Permit();
debug((" .. not yet!\n"));
goto top; /* sorry... can't exit */
}
debug((" .. yes!\n"));
/*
* Causes a new process to be created on next reference.
*/
DevNode->dn_Task = NULL;
TDRemChangeInt();
DiskRemoved();
HanCloseDown();
debug(("HanCloseDown returned. uninitsyslog in 2 seconds:\n"));
/*
* Remove debug, closedown, fall of the end of the world.
*/
exit:
#if HDEBUG
Delay(100L); /* This is dangerous! */
uninitsyslog();
#endif /* HDEBUG */
if (done & 2)
UnLoadSeg(DevNode->dn_SegList); /* This is real fun. We are still */
if (done & (2 | 1))
DevNode->dn_SegList = 0; /* Forbid()den, fortunately */
CloseLibrary((struct Library *)DOSBase);
/* Fall off the end of the world. Implicit Permit(). */
}
/*
* ChangeIntHand must be __geta4 if it is called directly through the
* ChangeInt.is_Code pointer, but then we can't be pure.
* If ChangeIntHand0 is called, __geta4 is done there via is_Data.
*/
__stkargs /*__geta4*/ void
ChangeIntHand(void)
{
DiskChanged = 1;
Signal(DosPort->mp_SigTask, PortMask);
}
/*
* Make a new struct FileLock, for DOS use. It is put on a singly linked
* list, which is attached to the same VolumeNode the old lock was on.
*
* Also note that we must ALWAYS be prepared to UnLock() or DupLock()
* any FileLocks we ever made, even if the volume in question has been
* removed and/or inserted into another drive with another FileSystem
* handler!
*
* DOS makes certain assumptions about LOCKS. A lock must minimally be a
* FileLock structure, with additional private information after the
* FileLock structure. The longword before the beginning of the structure
* must contain the length of structure + 4.
*
* NOTE!!!!! The workbench does not follow the rules and assumes it can copy
* lock structures. This means that if you want to be workbench
* compatible, your lock structures must be EXACTLY sizeof(struct
* FileLock). Also, it sometimes uses uninitialized values for the lock mode...
*/
struct FileLock *
NewFileLock(msfl, fl)
struct MSFileLock *msfl;
struct FileLock *fl;
{
struct FileLock *newlock;
struct DeviceList *volnode = NULL;
if (fl) {
volnode = BTOC(fl->fl_Volume);
}
if (volnode == NULL) {
volnode = VolNode;
debug(("volnode 0->%lx\n", volnode));
}
#if HDEBUG
if (volnode != VolNode) {
debug(("volnode != VolNode %lx != %lx\n",
volnode, VolNode));
}
if (volnode->dl_Task != DosPort) {
debug(("volnode->dl_Task != DosPort %lx != %lx\n",
volnode->dl_Task, DosPort));
}
#endif
if (newlock = dosalloc((ulong)sizeof (*newlock))) {
newlock->fl_Key = (ulong) msfl;
newlock->fl_Task = DosPort;
newlock->fl_Volume = (BPTR) CTOB(volnode);
Forbid();
newlock->fl_Link = volnode->dl_LockList;
volnode->dl_LockList = (BPTR) CTOB(newlock);
Permit();
} else
error = ERROR_NO_FREE_STORE;
return newlock;
}
/*
* This should be called before MSUnLock(), so that it may call
* MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
* I'm sorry for that.
*/
long
FreeFileLock(lock)
struct FileLock *lock;
{
struct FileLock *fl;
struct FileLock **flp;
struct DeviceList *volnode;
volnode = (struct DeviceList *)BTOC(lock->fl_Volume);
flp = (struct FileLock **) &volnode->dl_LockList;
for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
flp = (struct FileLock **)&fl->fl_Link;
if (fl == lock) {
*(BPTR *)flp = fl->fl_Link;
dosfree((ulong *)fl);
OpenCount--;
return DOSTRUE;
} else {
debug(("Huh?? Could not find filelock!\n"));
return DOSFALSE;
}
}
/*
* MakeFileLock allocates and initializes a new FileLock, using info
* from an existing FileLock. It always consumes the MSFileLock, even
* in case of failure.
*/
BPTR
MakeFileLock(msfl, fl, mode)
struct MSFileLock *msfl;
struct FileLock *fl;
long mode;
{
struct FileLock *newlock;
newlock = NULL;
if (msfl) {
if (newlock = NewFileLock(msfl, fl)) {
newlock->fl_Access = mode;
OpenCount++;
} else
MSUnLock(msfl);
}
return CTOB(newlock);
}
BOOL
AddVolNode(struct DeviceList *volnode)
{
long success = DOSFALSE;
if (DOSBase->dl_lib.lib_Version >= 37) {
struct DosList *dl;
dl = AttemptLockDosList(LDF_VOLUMES | LDF_WRITE);
if ((ULONG)dl & ~1) {
success = AddDosEntry((struct DosList *)volnode);
UnLockDosList(LDF_VOLUMES | LDF_WRITE);
}
} else {
struct DosInfo *di;
di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
Forbid();
volnode->dl_Next = di->di_DevInfo;
di->di_DevInfo = (long) CTOB(volnode);
Permit();
success = DOSTRUE;
}
return success;
}
/*
* Create Volume node and add to the device list. This will
* cause the WORKBENCH to recognize us as a disk. If we
* don't create a Volume node, Wb will not recognize us.
* However, we are a MESSYDOS: disk, Volume node or not.
*/
struct DeviceList *
NewVolNode(name, date)
char *name;
struct DateStamp *date;
{
struct DeviceList *volnode;
char *volname; /* This is my volume name */
if (volnode = dosalloc((ulong)sizeof (struct DeviceList))) {
if (volname = dosalloc(32L)) {
volname[0] = strlen(name);
strcpy(volname + 1, name); /* Make sure \0 terminated */
volnode->dl_Type = DLT_VOLUME;
volnode->dl_Task = DosPort;
volnode->dl_DiskType = IDDiskType;
volnode->dl_Name = (BSTR)CTOB(volname);
volnode->dl_VolumeDate = *date;
volnode->dl_MSFileLockList = (ULONG)NULL;
if (AddDosEntry((struct DosList *)volnode)== DOSFALSE)
goto error;
} else {
error:
dosfree((ulong *)volnode);
volnode = NULL;
}
} else {
error = ERROR_NO_FREE_STORE;
}
return volnode;
}
/*
* Get the current VolNode a new name from the volume label.
*/
void
NewVolNodeName()
{
if (VolNode) {
char *volname = BTOC(VolNode->dl_Name);
strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, L_8+L_3);
ZapSpaces(volname + 1, volname + 1 + L_8+L_3);
volname[0] = strlen(volname+1);
}
}
/*
* Remove Volume entry. Since DOS uses singly linked lists, we must
* (ugg) search it manually to find the link before our Volume entry.
*/
void
FreeVolNode(volnode)
struct DeviceList *volnode;
{
int deallocate = 0;
debug(("FreeVolNode %08lx\n", volnode));
if (volnode == NULL)
return;
if (DOSBase->dl_lib.lib_Version >= 37) {
struct DosList *dl;
dl = AttemptLockDosList(LDF_VOLUMES | LDF_WRITE);
/*
* Maybe the device list is locked when we are called as a result
* of a packet. Don't deadlock on that condition.
* Additionally, a hack from the Guru Book p. 393.
*/
if ((ULONG)dl & ~1) {
(void)RemDosEntry((struct DosList *)volnode);
deallocate = 1;
UnLockDosList(LDF_VOLUMES | LDF_WRITE);
} else {
/*
* Failed. Defer to later. If MustFreeVolNode was already set,
* that volume is remembered even though it shouldn't.
* I hope this is not very likely.
*/
debug(("MustFreeVolNode %lx := %lx\n", MustFreeVolNode, volnode));
MustFreeVolNode = volnode;
}
} else {
struct DosInfo *di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
struct DeviceList *dl;
void *dlp;
dlp = &di->di_DevInfo;
Forbid();
for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
dlp = &dl->dl_Next;
if (dl == volnode) {
*(BPTR *) dlp = dl->dl_Next;
deallocate = 1;
}
#if HDEBUG
else {
debug(("****PANIC: Unable to find volume node\n"));
}
#endif /* HDEBUG */
Permit();
}
if (deallocate) {
dosfree(BTOC(volnode->dl_Name));
dosfree((ulong *)volnode);
}
if (volnode == VolNode)
VolNode = NULL;
}
void
FreeVolNodeDeferred(void)
{
struct DeviceList *tmp = MustFreeVolNode;
MustFreeVolNode = NULL;
FreeVolNode(tmp);
}
/*
* This is also called from the real handler when the last lock on a
* volume is UnLock()ed, or the last file has been Close()d.
*/
int
MayFreeVolNode(volnode)
struct DeviceList *volnode;
{
if (volnode->dl_LockList == NULL) {
FreeVolNode(volnode);
return TRUE;
}
return FALSE;
}
#if defined(PROMISE_NOT_TO_DIE)
/*
* This function makes it possible to transfer locks from one handler to
* another, when the disk is being moved from one drive to another. The
* Amiga file system also does it. Try doing a "list df0:", pause it, put
* the disk in df1:, and continue. Unfortunately, passing FileLocks between
* handlers assumes that they will stick around forever. Therefore we make
* the user promise this by setting the PROMISE_NOT_TO_DIE flag.
*/
void RedirectLocks(struct DeviceList *volnode);
void
RedirectLocks(volnode)
struct DeviceList *volnode;
{
if (Interleave & PROMISE_NOT_TO_DIE) {
struct FileLock *fl;
fl = BTOC(volnode->dl_LockList);
while (fl) {
/*
* This is no good for their OpenCount...
* they can never die again!
* Alternatively, in DiskRemoved() the OpenCount could
* be decremented for each lock (and dl_Task cleared?).
*/
fl->fl_Task = volnode->dl_Task;
OpenCount++;
fl = BTOC(fl->fl_Link);
}
}
}
#endif
/*
* Our disk has been removed. Save the FileLocks in the dl_LockList,
* and let the handler save its MSFileLocks in the dl_MSFileLockList field.
* If it has nothing to save, forget about the volume, and return
* DOSTRUE.
* There is one subtlety that MSDiskRemoved must know about:
* If it MSUnLock()s the last lock on the volume, the VolNode is
* deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
* But then there is no place anymore to put NULL in, so that needs
* to be done first.
*/
long
DiskRemoved()
{
debug(("DiskRemoved %08lx\n", VolNode));
#if INPUTDEV
if (IDDiskType != ID_NO_DISK_PRESENT)
InputDiskRemoved();
#endif
if (VolNode == NULL) {
IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
return DOSTRUE;
}
VolNode->dl_Task = NULL;
MSDiskRemoved((struct LockList **)&VolNode->dl_MSFileLockList);
if (VolNode == NULL) { /* Could happen via MSDiskRemoved() */
return DOSTRUE;
}
VolNode = NULL;
return DOSFALSE;
}
/*
* Reconstruct everything from a Volume node
*/
void
DiskInserted(volnode)
struct DeviceList *volnode;
{
debug(("DiskInserted %08lx\n", volnode));
VolNode = volnode;
if (volnode) {
volnode->dl_Task = DosPort;
#if defined(PROMISE_NOT_TO_DIE)
RedirectLocks(volnode);
#endif
MSDiskInserted((struct LockList **)&volnode->dl_MSFileLockList, volnode);
volnode->dl_MSFileLockList = (BPTR)NULL;
#if INPUTDEV
if (IDDiskType != ID_NO_DISK_PRESENT)
InputDiskInserted();
#endif
}
}
/*
* Test if we have a DD or HD floppy right now.
* If the TD_GETDRIVETYPE fails or produces weird values, do nothing.
* Otherwise, select the correct sectors/track value, originally
* derived from the mountlist.
*/
void
CheckDriveType(void)
{
struct IOExtTD *req = DiskIOReq;
debug(("CheckDriveType()\n"));
req->iotd_Req.io_Command = TD_GETDRIVETYPE;
/*
* If this fails or gives weird values, it probably is not
* a floppy drive, and we don't mess with the defaults.
*/
if (MyDoIO(&req->iotd_Req) == 0) {
int spt;
switch (req->iotd_Req.io_Actual) {
case DRIVE3_5:
case DRIVE5_25:
debug(("DD floppy\n"));
spt = Partition.spt_dd;
break;
case DRIVE3_5_150RPM:
debug(("HD floppy\n"));
spt = Partition.spt_hd;
break;
default:
debug(("strange drive type: %d\n", req->iotd_Req.io_Actual));
goto no_floppy;
}
DefaultDisk.spt = spt;
if (Environ)
Environ->de_BlocksPerTrack = spt;
DefaultDisk.nsects = (Environ->de_HighCyl - Environ->de_LowCyl + 1) *
DefaultDisk.nsides * spt;
/*
* Suggest a minimum value for the number of FAT sectors.
* Here we assume all sectors are to be used for clusters, which is not
* really true, but simpler, and gives a conservative value. Besides,
* the number of available sectors also depends on the FAT size, so
* the whole calculation (if done correctly) would be recursive. In
* practice, it may occasionally suggest one sector too much.
*/
{
long nclusters;
long nbytes;
nclusters = MS_FIRSTCLUST + (DefaultDisk.nsects+DefaultDisk.spc-1)/
DefaultDisk.spc;
if (nclusters > 0xFF7) /* 16-bit FAT entries */
nbytes = nclusters * 2;
else /* 12-bit FAT entries */
nbytes = (nclusters * 3 + 1) / 2;
DefaultDisk.spf = (nbytes + DefaultDisk.bps - 1) / DefaultDisk.bps;
/* Hack for floppies */
if (DefaultDisk.spf < MS_SPF)
DefaultDisk.spf = MS_SPF;
}
}
no_floppy:;
}
struct DeviceList *
WhichDiskInserted()
{
char name[34];
struct DateStamp date;
struct DeviceList *dl = NULL;
CheckDriveType();
if (!Inhibited && IdentifyDisk(name, &date) == 0) {
struct DosInfo *di = BTOC(((struct RootNode *) DOSBase->dl_Root)->rn_Info);
byte *nodename;
int namelen = strlen(name);
for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
nodename = BTOC(dl->dl_Name);
if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
continue;
if (dl->dl_VolumeDate == date) /* Non-standard! Structure compare! */
break;
}
name[31] = '\0';
if (dl == NULL)
dl = NewVolNode(name, &date);
}
debug(("WhichDiskInserted() done\n"));
return dl;
}
void
DiskChange(void)
{
debug(("DiskChange\n"));
DiskChanged = 0;
DiskRemoved();
DiskInserted(WhichDiskInserted());
}
int
CheckRead(lock)
struct FileLock *lock;
{
if (lock && BTOC(lock->fl_Volume) != VolNode)
error = ERROR_DEVICE_NOT_MOUNTED;
else if (IDDiskType == ID_NO_DISK_PRESENT)
error = ERROR_NO_DISK;
else if (IDDiskType != ID_DOS_DISK)
error = ERROR_NOT_A_DOS_DISK;
return error;
}
int
CheckWrite(lock)
struct FileLock *lock;
{
if (CheckRead(lock))
/* nothing */ ;
else if (IDDiskState == ID_VALIDATING)
error = ERROR_DISK_NOT_VALIDATED;
else if (IDDiskState != ID_VALIDATED || WriteProtect)
error = ERROR_DISK_WRITE_PROTECTED;
return error;
}